package com.kai.service.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kai.service.data.request.sms.CheckSmsMailRequest;
import com.kai.service.data.request.system.UpdatePasswordRequest;
import com.kai.service.data.request.user.CreateUserInfoRequest;
import com.kai.service.data.request.user.PagingUserInfoRequest;
import com.kai.service.data.request.user.RegisterUserRequest;
import com.kai.service.data.request.user.UpdateUserInfoRequest;
import com.kai.service.data.response.user.UserInfoResponse;
import com.kai.service.enums.DeleteStatusEnum;
import com.kai.service.enums.ResultCodeEnum;
import com.kai.service.exception.GenericException;
import com.kai.service.sms.service.ISmsMailService;
import com.kai.service.user.entity.User;
import com.kai.service.user.entity.UserRole;
import com.kai.service.user.mapper.UserMapper;
import com.kai.service.user.service.IUserRoleService;
import com.kai.service.user.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author wjk
 * @since 2021-11-22
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Value("${default.roleId:}")
    private Integer roleId; // 博客注册用户默认角色

    @Value("${default.imgUrl:}")
    private String imgUrl; // 博客注册用户默认头像

    @Autowired
    private IUserRoleService userRoleService;

    @Autowired
    private ISmsMailService smsMailService;

    /**
     * 校验用户已存在
     *
     * @param username
     * @return
     */
    @Override
    public void checkUserExist(String username) {
        User user = this.getUser(username);
        if (Objects.nonNull(user)) {
            throw new GenericException(ResultCodeEnum.USER_EXISTED);
        }
    }

    /**
     * 校验用户不存在
     *
     * @param username
     * @return
     */
    @Override
    public User checkUserNotExist(String username) {
        User user = this.getUser(username);
        if (Objects.isNull(user)) {
            throw new GenericException(ResultCodeEnum.USER_NOT_EXIST);
        }

        return user;
    }

    /**
     * 获取账号信息
     *
     * @param username
     * @return
     */
    private User getUser(String username) {
        return this.lambdaQuery()
                .eq(User::getUsername, username)
                .eq(User::getIsDeleted, DeleteStatusEnum.NO.getCode())
                .one();
    }

    /**
     * 分页获取所有账号信息
     * @param pagingUserInfoRequest
     * @return
     */
    @Override
    public IPage<UserInfoResponse> pagingUserInfo(PagingUserInfoRequest pagingUserInfoRequest) {
        IPage<User> userIPage = this.lambdaQuery()
                .eq(User::getIsDeleted, DeleteStatusEnum.NO.getCode())
                .eq(Objects.nonNull(pagingUserInfoRequest.getUserId()), User::getId, pagingUserInfoRequest.getUserId())
                .eq(StringUtils.isNotBlank(pagingUserInfoRequest.getUsername()), User::getUsername, pagingUserInfoRequest.getUsername())
                .like(StringUtils.isNotBlank(pagingUserInfoRequest.getNickName()), User::getNickName, pagingUserInfoRequest.getNickName())
                .orderByDesc(User::getCreateDatetime)
                .page(new Page<>(pagingUserInfoRequest.getPageIndex(), pagingUserInfoRequest.getPageSize()));

        List<UserInfoResponse> userInfoResponseList = userIPage.getRecords().stream().map(UserInfoResponse::new).collect(Collectors.toList());

        return new Page<UserInfoResponse>()
                .setRecords(userInfoResponseList)
                .setCurrent(userIPage.getCurrent())
                .setTotal(userIPage.getTotal())
                .setPages(userIPage.getPages())
                .setSize(userIPage.getSize());
    }

    /**
     * 根据id获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserInfoResponse getUserInfo(Long userId) {
        User user = this.getById(userId);
        if (Objects.isNull(user)){
            throw new GenericException(ResultCodeEnum.USER_NOT_EXIST);
        }

        return new UserInfoResponse(user);
    }

    /**
     * 用户注册
     *
     * @param registerUserRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Boolean registerUser(RegisterUserRequest registerUserRequest) {
        Date nowDate = new Date();
        String username = registerUserRequest.getUsername();
        String password = registerUserRequest.getPassword();
        Integer verificationCode = registerUserRequest.getVerificationCode();

        // 校验账号格式
        if (!Validator.isEmail(username) && !Validator.isMobile(username)){
            throw new GenericException(ResultCodeEnum.INCORRECT_ACCOUNT_FORMAT);
        }

        // 校验用户已经存在
        this.checkUserExist(username);

        // 校验验证码
        CheckSmsMailRequest checkSmsMailRequest = new CheckSmsMailRequest();
        checkSmsMailRequest.setUsername(username);
        checkSmsMailRequest.setVerificationCode(verificationCode);
        smsMailService.checkSmsVerificationCode(checkSmsMailRequest);

        User user = new User();
        user.setUsername(username)
                .setPassword(new BCryptPasswordEncoder().encode(password))
                .setNickName(username)
                .setCreateDatetime(nowDate)
                .setUpdateDatetime(nowDate)
                .setImgUrl(imgUrl);
        this.save(user);

        // 添加用户角色
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId()).setRoleId(roleId);

        return userRoleService.save(userRole);
    }

    /**
     * 新增用户信息
     *
     * @param createUserInfoRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Boolean createUserInfo(CreateUserInfoRequest createUserInfoRequest) {
        Date nowDate = new Date();

        // 校验用户已经存在
        this.checkUserExist(createUserInfoRequest.getUsername());

        User user = new User();
        BeanUtils.copyProperties(createUserInfoRequest, user);

        user.setIsDeleted(DeleteStatusEnum.NO.getCode())
                .setPassword(new BCryptPasswordEncoder().encode(createUserInfoRequest.getPassword()))
                .setCreateDatetime(nowDate)
                .setUpdateDatetime(nowDate);
        this.save(user);

        // 添加用户角色
        addUserRole(user.getId(), createUserInfoRequest.getUserRoleIds());

        return Boolean.TRUE;
    }

    /**
     * 修改用户信息
     *
     * @param userId
     * @param updateUserInfoRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Boolean updateUserInfo(Long userId, UpdateUserInfoRequest updateUserInfoRequest) {
        Date date = new Date();
        User user = this.getById(userId);
        if (null == user || !user.getUsername().equals(updateUserInfoRequest.getUsername())){
            throw new GenericException(ResultCodeEnum.USER_NOT_EXIST);
        }

        BeanUtil.copyProperties(updateUserInfoRequest, user);
        user.setId(userId).setUpdateDatetime(date);
        this.updateById(user);

        // 修改用户角色
        if (!Objects.equals("web", updateUserInfoRequest.getSystemCode())) {
            userRoleService.getBaseMapper().delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId));
            addUserRole(userId, updateUserInfoRequest.getUserRoleIds());
        }

        return Boolean.TRUE;
    }

    /**
     * 修改用户密码
     *
     * @param userId
     * @param updatePasswordRequest
     * @return
     */
    @Override
    public Boolean changePassword(Long userId, UpdatePasswordRequest updatePasswordRequest) {
        String username = updatePasswordRequest.getUsername();
        String oldPassword = updatePasswordRequest.getOldPassword();
        String newPassword = updatePasswordRequest.getNewPassword();

        User user = this.getById(userId);
        if (null == user || !user.getUsername().equals(username)){
            throw new GenericException(ResultCodeEnum.USER_NOT_EXIST);
        }

        if (!new BCryptPasswordEncoder().matches(user.getPassword(), oldPassword)) {
            throw new GenericException(ResultCodeEnum.USERNAME_PASSWORD_ERROR);
        }

        user.setPassword(new BCryptPasswordEncoder().encode(newPassword));

        return this.updateById(user);
    }

    /**
     * 重设密码
     *
     * @param registerUserRequest
     * @return
     */
    @Override
    public Boolean resetPassword(RegisterUserRequest registerUserRequest) {
        String username = registerUserRequest.getUsername();
        String password = registerUserRequest.getPassword();
        Integer verificationCode = registerUserRequest.getVerificationCode();

        // 校验用户不存在
        User user = this.checkUserNotExist(username);

        // 校验验证码
        CheckSmsMailRequest checkSmsMailRequest = new CheckSmsMailRequest();
        checkSmsMailRequest.setUsername(username);
        checkSmsMailRequest.setVerificationCode(verificationCode);
        smsMailService.checkSmsVerificationCode(checkSmsMailRequest);

        user.setPassword(new BCryptPasswordEncoder().encode(password)).setUpdateDatetime(new Date());

        return this.updateById(user);
    }

    /**
     * 删除用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public Boolean deleteUserInfo(Long userId) {
        boolean isRemove = this.lambdaUpdate()
                .set(User::getIsDeleted, DeleteStatusEnum.YES.getCode())
                .set(User::getUpdateDatetime, new Date())
                .eq(User::getId, userId)
                .remove();

        if (!isRemove) {
            throw new GenericException(ResultCodeEnum.USER_NOT_EXIST);
        }

        return Boolean.TRUE;
    }

    /**
     * 添加用户角色
     *
     * @param userId
     * @param userRoleIds
     */
    public void addUserRole(Long userId, List<Integer> userRoleIds){
        List<UserRole> userRoleList = new ArrayList<>();
        userRoleIds.forEach(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(userId).setRoleId(roleId);
            userRoleList.add(userRole);
        });
        userRoleService.saveBatch(userRoleList);
    }
}
